home *** CD-ROM | disk | FTP | other *** search
/ APDL Eductation Resources / APDL Eductation Resources.iso / programs / astronomy / skyview / !SkyView / c / Markers < prev    next >
Encoding:
Text File  |  1993-08-26  |  21.3 KB  |  660 lines

  1. /********************************************************/
  2. /*              Markers Module for SkyView              */
  3. /*                                                      */
  4. /*                  (c)1992 N P Hawkes                  */
  5. /*                                                      */
  6. /*    Displays markers at regular RA & Dec intervals    */
  7. /********************************************************/
  8.  
  9. #include "menu.h"
  10. #include "dbox.h"
  11. #include "bbc.h"
  12. #include "wimpt.h"
  13. #include "dbox.h"
  14. #include "string.h"
  15. #include "event.h"
  16.  
  17. #include "sv_header.h"
  18. #include "markers.h"
  19. #include "radec.h"
  20.  
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23.  
  24. /********************************************************/
  25. /*                     Constants                        */
  26. /********************************************************/
  27. #define DISP_NAME "Markers"    /* Entry in Display menu.*/
  28. #define SEL_NAME  "Marker..."  /* Entry in Select menu. */
  29. #define SELBOX_NAME "MarkersSel" /* Name of Sel dbox.   */
  30.  
  31. #define HORALT (REAL)0.0044      /* Altitude of horizon.*/
  32.  
  33. /* No. of Declination values (starting at -90 deg.):    */
  34. #define NDEC 19
  35.  
  36. /*No. of RA values at each Dec value (starting at 0 hr):*/
  37. static int nra[NDEC] =
  38.   {1, 12, 12, 12, 12, 12, 12, 12, 12, 24,
  39.       12, 12, 12, 12, 12, 12, 12, 12, 1};
  40.  
  41. /* Constants relating to Selection dialogue box.        */
  42. enum {
  43.   box_cancel = -1,  /* Response cancelling the dbox.    */
  44.   sel_ok     =  0,  /* OK button.                       */
  45.   sel_cancel,       /* Cancel button.                   */
  46.   dec_dn,           /* Button to decrease declination.  */
  47.   dec_up,           /* Button to increase declination.  */
  48.   dec_field,        /* Field No. for declination.       */
  49.   ra_dn,            /* Button to decrease rt ascension. */
  50.   ra_up,            /* Button to increase rt ascension. */
  51.   ra_field          /* Field No. for rt ascension.      */
  52. };
  53.  
  54. /********************************************************/
  55. /*                New types of variable.                */
  56. /********************************************************/
  57. /* Structure describing one marker.                     */
  58. typedef struct {
  59.   REAL ra;          /* Right ascension (radians).       */
  60.   REAL dec;         /* Declination (radians).           */
  61.   int  horiz_id;    /* id in Horiz window.              */
  62.   int  vert_id;     /* id in Vert window.               */
  63.   int  hi;          /* Markers in range lo (inclusive)  */
  64.   int  lo;          /* to hi (exclusive) all have       */
  65.                     /* declination 'dec'.               */
  66. } markerstr;
  67.  
  68. /********************************************************/
  69. /*                  Global Variables                    */
  70. /********************************************************/
  71. static BOOL display_flag = FALSE;  /* 'Enabled' flag.   */
  72. static BOOL list_valid   = FALSE;  /* TRUE if list valid*/
  73. static int moduleid;               /* Module ID.        */
  74.  
  75. static int marker_count = 0;   /* Total no. of markers. */
  76. static markerstr *marker_data; /* Ptr to main data store*/
  77.  
  78. static dbox d_sel;            /* Selection dbox.        */
  79. static int sel_id = 97;       /* ID of most recent sel- */
  80.                               /* ection made via dbox.  */
  81.  
  82. /********************************************************/
  83. /*                 Function Prototypes                  */
  84. /********************************************************/
  85. static void markers_buildfn(void);
  86. static BOOL markers_displayfn(BOOL *enabptr);
  87. static os_error *markers_plotfn(int x, int y, int id);
  88. static void markers_infofn(int id);
  89. static void markers_selectfn(selectfn_reasoncode reason);
  90. static int  selectionbox(void);
  91. static void selection_details(void);
  92. static void selbox_load(int id);
  93. static int selbox_buttons(int start_id);
  94. static int find_lower_dec(int old_id, REAL target);
  95. static int find_higher_dec(int old_id, REAL target);
  96. static int find_lower_ra(int old_id);
  97. static int find_higher_ra(int old_id);
  98. static int ra_search(int lo, int hi, REAL target);
  99.  
  100. /********************************************************/
  101. /*                Initialisation Function               */
  102. /********************************************************/
  103. BOOL markers_initfn(int moduleno, modulestr *markers)
  104. {
  105.   int i, j;
  106.   int first;
  107.   REAL ddec;      /* Interval of Declination (radians). */
  108.   REAL dra;       /* Interval of Rt Ascension (radians).*/
  109.   int marker_id    = 0;  /* id number of marker.        */
  110.  
  111. /* Record the module number of this module.             */
  112.   moduleid = moduleno;
  113.  
  114.  
  115. /*        Allocate memory for main data store.          */
  116.  
  117. /* Calculate how many markers there are.                */
  118.   for (i=0; i<NDEC; i++)
  119.     marker_count += nra[i];
  120. /* Allocate memory.  Quit if allocation fails.          */
  121.   marker_data = calloc(marker_count, sizeof(markerstr));
  122.   if (marker_data == NULL) return FALSE;
  123.  
  124. /*            Generate the data array.                  */
  125.  
  126. /* Calculate declination interval in radians.           */
  127.   if (NDEC > 1)
  128.     ddec = PI/(NDEC - 1);
  129.  
  130. /* Calculate data for all markers at each dec. value.   */
  131.   for (i=0; i<NDEC; i++)
  132.   {
  133.   /* Remember first id number at this dec.              */
  134.     first = marker_id;
  135.   /* Find interval of right ascension.                  */
  136.     dra = (REAL)2.0*PI/nra[i];
  137.   /* Deal with each ra value in turn.                   */
  138.     for (j=0; j<nra[i]; j++)
  139.     {
  140.       marker_data[marker_id].ra  = j * dra;
  141.       marker_data[marker_id].dec = i * ddec - PIby2;
  142.       marker_data[marker_id].lo = first;
  143.       marker_data[marker_id].hi = first + nra[i];
  144.       marker_id++;
  145.     }
  146.   }
  147.  
  148.  
  149. /* Fill in the fields of the modulestr.                 */
  150.   markers->buildfn  = markers_buildfn;
  151.   markers->selectfn = markers_selectfn;
  152.   markers->dispfn   = markers_displayfn;
  153.   markers->infofn   = markers_infofn;
  154.   markers->initial  = display_flag;
  155.   markers->display_entry = DISP_NAME;
  156.   markers->display_menu  = NULL;
  157.   markers->select_entry  = SEL_NAME;
  158.   markers->select_menu   = NULL;
  159.  
  160.   return TRUE;
  161. }
  162.  
  163. /********************************************************/
  164. /*                 List-Building Function               */
  165. /********************************************************/
  166. static void markers_buildfn(void)
  167. {
  168.   int i;
  169.   plotobj marker;
  170.  
  171.   /* Bounding box of plotting symbol, relative to       */
  172.   /* position of symbol:                                */
  173.   static wimp_box size = {-10, -10, 10, 10};
  174.  
  175. /* If module is currently disabled, ignore call to list-*/
  176. /* building function, and set flag to indicate that     */
  177. /* module does not have valid data in the plotting list.*/
  178.   if (!display_flag)
  179.   {
  180.     list_valid = FALSE;
  181.     return;
  182.   }
  183.  
  184. /* If module is currently enabled, build plotting list  */
  185. /* and set flag to indicate module has valid data.      */
  186.   list_valid = TRUE;
  187.  
  188. /* For each marker in turn:                             */
  189.   for (i=0; i<marker_count; i++)
  190.   {
  191.  
  192.     /* Build plotobj.                                   */
  193.     marker.id = i;
  194.     marker.module = moduleid;
  195.     marker.plotfn  = markers_plotfn;
  196.     radec_altaz(marker_data[i].ra, marker_data[i].dec, &ob_data, ob_data.sid,
  197.       &marker.alt, &marker.azim);
  198.     marker.size = size;
  199.  
  200.     /* Offer this to the main program.                  */
  201.     addobj(marker, &marker_data[i].horiz_id, &marker_data[i].vert_id);
  202.  
  203.   }
  204.  
  205.   return;
  206. }
  207.  
  208.  
  209.   
  210. /********************************************************/
  211. /*              Object-Selecting Function               */
  212. /********************************************************/
  213. static void markers_selectfn(selectfn_reasoncode reason)
  214. {
  215.   int marker_id;
  216.  
  217.   switch (reason)
  218.   {
  219.     case new_selection:
  220.       /* Using dialogue box, determine which marker is  */
  221.       /* to be selected.   A return of -1 indicates     */
  222.       /* dialogue was cancelled.                        */
  223.       marker_id = selectionbox();
  224.       if (marker_id == -1)
  225.       {
  226.         selection.selected_OK = FALSE;
  227.         return;
  228.       }
  229.       /* Valid selection has been made.                 */
  230.       /* Remember id of selected marker for next time,  */
  231.       /* and give the id number to the main program.    */
  232.       sel_id       = marker_id;
  233.       selection.id = marker_id;
  234.       /*  Flag the selection as successful.             */
  235.       selection.selected_OK = TRUE;
  236.       /* Fill in Selection details for requested marker.*/
  237.       selection_details();
  238.       break;
  239.  
  240.     case window_selection:
  241.       /* A selection has been made by clicking in a     */
  242.       /* window.                                        */
  243.     case recalculate_data:
  244.       /* Observer details have changed, and plotting    */
  245.       /* lists have been rebuilt.                       */
  246.       /*                                                */
  247.       /* In both cases, the ID of the marker is already */
  248.       /* in selection.id                                */
  249.       selection_details();
  250.       break;
  251.  
  252.     case timeonly_recalculate:
  253.       /* As recalculate_data, but only the time of day  */
  254.       /* (and possibly the direction of view - this is  */
  255.       /* is of no interest) have changed.               */
  256.       /* This simplifies the calculation.               */
  257.       marker_id = selection.id;
  258.       selection.horiz_id    = marker_data[marker_id].horiz_id;
  259.       selection.vert_id     = marker_data[marker_id].vert_id;
  260.       /* Decide if it can be seen now.                  */
  261.       selection.now         = selection.horiz_id != NOWHERE || \
  262.                               selection.vert_id  != NOWHERE;
  263.       break;
  264.  
  265.     case sel_info_request:
  266.       /* Write info into text buffer.                   */
  267.       {
  268.       REAL rah;    /* Right Ascension in hours.         */
  269.       REAL decd;   /* Declination in degrees.           */
  270.  
  271.       marker_id = selection.id;
  272.  
  273.       rah  = marker_data[marker_id].ra * (REAL)12.0 / PI;
  274.       decd = marker_data[marker_id].dec / CONV;
  275.  
  276.       sprintf(infoptr,"%s%s%.1f%s%s%.1f%s",
  277.                   "Marker\n",
  278.                   "RA ", (double)rah, " hours\n",
  279.                   "Dec ",(double)decd,"°");
  280.       }
  281.       break;
  282.  
  283.     default:
  284.       /* Unknown option.  Do nothing.                   */
  285.       break;
  286.  
  287.     }
  288.  
  289.   return;
  290. }
  291.  
  292. /*------------------------------------------------------*/
  293. /* Function to obtain id number of marker to be selected*/
  294. /*             by means of a dialogue box.              */
  295. /*         Returns -1 if dialogue is cancelled.         */
  296. /*------------------------------------------------------*/
  297. static int selectionbox(void)
  298. {
  299.   int result;              /*Result of dialogue.        */
  300.  
  301. /* Ensure menu has gone, create dbox, load it with info */
  302. /* and put it on display.  (If not already done.)       */
  303.   if (!dbox_persisting)
  304.   {
  305.     event_clear_current_menu();
  306.     d_sel = dbox_new(SELBOX_NAME);
  307.     if (d_sel == NULL) return -1;
  308.     selbox_load(sel_id);
  309.     dbox_show(d_sel);
  310.   }
  311.  
  312. /* Deal with button clicks until user clicks OK, or     */
  313. /* clicks Cancel with left hand mouse button, or clicks */
  314. /* outside dbox. Result is chosen id, or -1 if cancelled*/
  315.   result = selbox_buttons(sel_id);
  316.  
  317. /* Delete dbox if it is not required to persist.        */
  318.   if (!dbox_persisting) dbox_dispose(&d_sel);
  319.  
  320. /* Return the chosen value.                             */
  321.   return result;
  322. }
  323.  
  324. /*------------------------------------------------------*/
  325. /*   Function to load info from marker No. 'id' into    */
  326. /*                    selection dbox                    */
  327. /*------------------------------------------------------*/
  328. static void selbox_load(int id)
  329. {
  330.  
  331.   REAL rah;    /* Right Ascension in hours.             */
  332.   REAL decd;   /* Declination in degrees.               */
  333.   char numbuf[32];
  334.  
  335.   rah  = marker_data[id].ra * (REAL)12.0 / PI;
  336.   decd = marker_data[id].dec / CONV;
  337.  
  338. /* Get RA of marker into string form.                   */
  339.   sprintf(numbuf, "%.1f hours", (double)rah);
  340. /* Write RA into ra field of dbox.                      */
  341.   dbox_setfield(d_sel, ra_field, numbuf);
  342.  
  343. /* Get Dec of marker into string form.                  */
  344.   sprintf(numbuf, "%+.1f°", (double)decd);
  345. /* Write Dec into dec field of dbox.                    */
  346.   dbox_setfield(d_sel, dec_field, numbuf);
  347.  
  348.   return;
  349. }
  350.  
  351. /*------------------------------------------------------*/
  352. /* Function to deal with button clicks in Selection box.*/
  353. /*------------------------------------------------------*/
  354. static int selbox_buttons(int start_id)
  355. {
  356. /* start_id is ID number on show initially.             */
  357.  
  358. /* new_id is ID number currently on show.               */
  359.   int new_id = start_id;
  360.  
  361.   int response;    /* Latest button No. clicked by user.*/
  362.   REAL ra_target;  /* RA of marker is to be as close to */
  363.                    /* this as possible.                 */
  364.  
  365.   ra_target = marker_data[start_id].ra;
  366.  
  367. /* Loop until user clicks on OK, or on Cancel with left-*/
  368. /* hand mouse button, or closes dbox with a 'harmful    */
  369. /* event' (eg clicking outside dbox).                   */
  370.   for (;;)
  371.   {
  372.  
  373.   /* Get field number of latest click.                  */
  374.     response = dbox_fillin(d_sel);
  375.  
  376.   /* Take appropriate action.                           */
  377.     switch (response) {
  378.  
  379.       case box_cancel:
  380.       /* dbox cancelled.  Close it and return -1.       */
  381.         dbox_persisting = FALSE;
  382.         return -1;
  383.  
  384.       case sel_ok:
  385.       /* Return current id number.  Retain dbox if click*/
  386.       /* was with Adjust.                               */
  387.         dbox_persisting = dbox_persist();
  388.         return new_id;
  389.  
  390.       case sel_cancel:
  391.       /* If normal click, close dbox and return -1.     */
  392.       /* If Adjust, reload initial id and keep looping. */
  393.         if (dbox_persist())
  394.         {
  395.           new_id = start_id;
  396.           ra_target = marker_data[start_id].ra;
  397.           selbox_load(new_id);
  398.         }
  399.         else
  400.         {
  401.           dbox_persisting = FALSE;
  402.           return -1;
  403.         }
  404.         break;
  405.  
  406.       case dec_dn:
  407.       /* Decrease declination.  Find marker with next   */
  408.       /* lower dec, and RA as close to ra_target as poss*/
  409.         new_id = find_lower_dec(new_id, ra_target);
  410.       /* Load new info into dbox.                       */
  411.         selbox_load(new_id);
  412.         break;
  413.  
  414.       case dec_up:
  415.       /* Increase declination.  Find marker with next   */
  416.       /* higher dec, and RA as close to ra_target as    */
  417.       /* possible.                                      */
  418.         new_id = find_higher_dec(new_id, ra_target);
  419.       /* Load new info into dbox.                       */
  420.         selbox_load(new_id);
  421.         break;
  422.  
  423.       case ra_dn:
  424.       /* Decrease Right Ascension.                      */
  425.         new_id = find_lower_ra(new_id);
  426.       /* Update ra_target.                              */
  427.         ra_target = marker_data[new_id].ra;
  428.       /* Load new info into dbox.                       */
  429.         selbox_load(new_id);
  430.         break;
  431.  
  432.       case ra_up:
  433.       /* Increase Right Ascension.                      */
  434.         new_id = find_higher_ra(new_id);
  435.       /* Update ra_target.                              */
  436.         ra_target = marker_data[new_id].ra;
  437.       /* Load new info into dbox.                       */
  438.         selbox_load(new_id);
  439.         break;
  440.  
  441.     }
  442.   }
  443. }
  444.  
  445. /*------------------------------------------------------*/
  446. /*  Functions to find new marker id which most closely  */
  447. /*        fits the change requested by the user.        */
  448. /*------------------------------------------------------*/
  449. static int find_lower_dec(int old_id, REAL target)
  450. {
  451. /* Search for id having 'dec' one increment lower than  */
  452. /* current marker, and 'ra' as close as poss. to target.*/
  453.  
  454.   int old_lo; /* First id with the current value of dec.*/
  455.   int dum_id; /* Used to obtain search range.           */
  456.   int new_lo; /* Start of range to be searched for ra.  */
  457.   int new_hi; /* End of search range (exclusive).       */
  458.  
  459.   old_lo = marker_data[old_id].lo;
  460.  
  461. /*      Establish range of ids to be searched.          */
  462. /* Obtain an id which has the desired declination.      */
  463. /* Cycle round to top of dec range if necessary.        */
  464.   dum_id = (old_lo > 0 ? old_lo - 1 : marker_count - 1);
  465. /* Use this id to get range of ids with desired dec.    */
  466.   new_lo = marker_data[dum_id].lo;
  467.   new_hi = marker_data[dum_id].hi;
  468.  
  469. /* Return id within this range which has closest ra.    */
  470.   return ra_search(new_lo, new_hi, target);
  471. }
  472.  
  473. static int ra_search(int lo, int hi, REAL target)
  474. {
  475.   REAL min_error = (REAL)2.0*PI;
  476.   REAL error;
  477.   int  id;
  478.   int  nearest = 0;
  479.  
  480.   for (id=lo; id<hi; id++)
  481.   {
  482.     error = marker_data[id].ra - target;
  483.     if (error < (REAL)0.0) error = -error;
  484.     if (error < min_error)
  485.     {
  486.       min_error = error;
  487.       nearest = id;
  488.     }
  489.   }
  490.   return nearest;
  491. }
  492.  
  493. static int find_higher_dec(int old_id, REAL target)
  494. {
  495. /* Search for id having 'dec' one increment higher than */
  496. /* current marker, and 'ra' as close as poss. to target.*/
  497.  
  498.   int old_hi; /* Last id with the current value of dec. */
  499.   int dum_id; /* Used to obtain search range.           */
  500.   int new_lo; /* Start of range to be searched for ra.  */
  501.   int new_hi; /* End of search range (exclusive).       */
  502.  
  503.   old_hi = marker_data[old_id].hi;
  504.  
  505. /*      Establish range of ids to be searched.          */
  506. /* Obtain an id which has the desired declination.      */
  507. /* Cycle round to botttom of dec range if necessary.    */
  508.   dum_id = (old_hi >= marker_count ? 0 : old_hi);
  509. /* Use this id to get range of ids with desired dec.    */
  510.   new_lo = marker_data[dum_id].lo;
  511.   new_hi = marker_data[dum_id].hi;
  512.  
  513. /* Return id within this range which has closest ra.    */
  514.   return ra_search(new_lo, new_hi, target);
  515.  
  516. }
  517.  
  518. static int find_lower_ra(int old_id)
  519. {
  520.   int new_id = old_id - 1;
  521.  
  522.   if (new_id < marker_data[old_id].lo)
  523.     new_id = marker_data[old_id].hi - 1;
  524.  
  525.   return new_id;
  526. }
  527.  
  528. static int find_higher_ra(int old_id)
  529. {
  530.   int new_id = old_id + 1;
  531.  
  532.   if (new_id >= marker_data[old_id].hi)
  533.     new_id = marker_data[old_id].lo;
  534.  
  535.   return new_id;
  536. }
  537.  
  538.  
  539. /*------------------------------------------------------*/
  540. /*  Function to fill in selection details of selected   */
  541. /*   marker (viewing directions and times for rising,   */
  542. /*             setting, culminating etc).               */
  543. /*------------------------------------------------------*/
  544. static void selection_details(void)
  545. {
  546.   double ch;    /* cos of hour angle at horizon.        */
  547.   BOOL riset;   /* Whether object rises & sets or not.  */
  548.   BOOL culmin;  /* Whether object culminates or not.    */
  549.  
  550. /* ID number of marker is in selection.id               */
  551.   int id = selection.id;
  552.  
  553. /* Record window IDs of selected marker.                */
  554.   selection.horiz_id    = marker_data[id].horiz_id;
  555.   selection.vert_id     = marker_data[id].vert_id;
  556.  
  557. /* Find out if it can be seen now.                      */
  558.   selection.now         = selection.horiz_id != NOWHERE || \
  559.                           selection.vert_id  != NOWHERE;
  560.  
  561. /* Find out if marker rises, sets or culminates today.  */
  562. /* (After setting effective altitude of horizon.)       */
  563.   radec_sethoriz(HORALT);
  564.  
  565.   radec_phenomena(marker_data[id].ra, marker_data[id].dec, &ob_data,
  566.                   &ch, &riset, &culmin);
  567.   selection.rising      = riset;
  568.   selection.setting     = riset;
  569.   selection.culminating = culmin;
  570.  
  571. /* Fill in details for each phenomenon which occurs.    */
  572.  
  573.   if (selection.rising)
  574.     radec_rise_details(
  575.         marker_data[id].ra, marker_data[id].dec, &ob_data, ch,
  576.         &selection.rise_azim,
  577.         &selection.rise_hour,
  578.         &selection.rise_min);
  579.  
  580.   if (selection.setting)
  581.     radec_set_details(
  582.         marker_data[id].ra, marker_data[id].dec, &ob_data, ch,
  583.         &selection.set_azim,
  584.         &selection.set_hour,
  585.         &selection.set_min);
  586.  
  587.   if (selection.culminating)
  588.     radec_cul_details(
  589.         marker_data[id].ra, marker_data[id].dec, &ob_data,
  590.         &selection.cul_alt,
  591.         &selection.cul_azim,
  592.         &selection.cul_hour,
  593.         &selection.cul_min);
  594.  
  595.   return;
  596. }
  597.  
  598. /********************************************************/
  599. /*                   Display Function                   */
  600. /********************************************************/
  601. static BOOL markers_displayfn(BOOL *enabptr)
  602. {
  603. /* Toggle Enable/Disable flag.                          */
  604.   display_flag = !display_flag;
  605.  
  606. /* Inform main program of new status.                   */
  607.   *enabptr = display_flag;
  608.  
  609. /* If module is now enabled, but does not have valid    */
  610. /* data in the plotting list, call the list-building fn.*/
  611.   if (display_flag && !list_valid)
  612.     markers_buildfn();
  613.  
  614. /* Windows will always need updating.                   */
  615.   return TRUE;
  616. }
  617.  
  618.  
  619. /********************************************************/
  620. /*                   Plotting Function                  */
  621. /********************************************************/
  622. static os_error *markers_plotfn(int x, int y, int id)
  623. {
  624.   os_error *errptr;
  625.  
  626. /* Set foreground graphics colour to Wimp colour 10     */
  627.   errptr = sv_setcolour(10);
  628.   if (errptr != NULL) return errptr;
  629.  
  630. /* Draw a suitable symbol at the given coordinates.     */
  631.   errptr = bbc_move(x-8, y);
  632.   if (errptr != NULL) return errptr;
  633.   errptr = bbc_draw(x+8, y);
  634.   if (errptr != NULL) return errptr;
  635.   errptr = bbc_move(x, y-8);
  636.   if (errptr != NULL) return errptr;
  637.   
  638.   return   bbc_draw(x, y+8);
  639. }
  640.  
  641.  
  642. /********************************************************/
  643. /*                     Info Function                    */
  644. /********************************************************/
  645. static void markers_infofn(int id)
  646. {
  647.   REAL rah;    /* Right Ascension in hours.           */
  648.   REAL decd;   /* Declination in degrees.             */
  649.  
  650.   rah  = marker_data[id].ra * (REAL)12.0 / PI;
  651.   decd = marker_data[id].dec / CONV;
  652.  
  653.   sprintf(infoptr,"%s%s%.1f%s%s%.1f%s",
  654.                   "Marker\n",
  655.                   "RA ", (double)rah, " hours\n",
  656.                   "Dec ",(double)decd,"°");
  657.  
  658.   return;
  659. }
  660.